package top.livepan.system.controller;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.livepan.server.BaseController;
import com.livepan.server.error.BusinessException;
import com.livepan.server.error.EmBusinessError;
import com.livepan.server.response.CommonReturnType;
import com.livepan.server.service.SubmissionService;
import com.livepan.server.service.UserService;
import com.livepan.server.service.model.UserModel;
import com.livepan.server.utils.*;
import org.apache.http.util.TextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.livepan.system.controller.viewobject.UserProfileVO;
import top.livepan.system.controller.viewobject.UserVO;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RestController("user")
@RequestMapping(value = "/user", method = {RequestMethod.POST})
public class UserController extends BaseController {
    public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";

    private final Logger LOG = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private SubmissionService submissionService;

    @Autowired
    public RedisTemplate redisTemplate;


    @RequestMapping("/userList")
    @ResponseBody
    public CommonReturnType getUserList()
            throws BusinessException {
        List<UserModel> userModelList = userService.getUserList();
        List<UserVO> userVOList = userModelList
                .stream().map(this::convertFromUserModel).collect(Collectors.toList());

        return CommonReturnType.create(userVOList);
    }

    @RequestMapping("/getByTelephone")
    @ResponseBody
    public CommonReturnType getUserByTelephone(@RequestParam(name = "telephone") String telephone)
            throws BusinessException {
        UserModel userModel = userService.getUserByTelePhone(telephone);

        if (userModel == null) {
            throw new BusinessException(EmBusinessError.USER_NOT_EXIT);
        }
        UserVO userVO = convertFromUserModel(userModel);
        return CommonReturnType.create(userVO);
    }


    @RequestMapping("/get")
    @ResponseBody
    public CommonReturnType getUserInfo() throws BusinessException {
        UserModel userModel = getUserModelFromSession();


        UserVO userVO = convertFromUserModel(userModel);
        return CommonReturnType.create(userVO);
    }

    @RequestMapping(value = "/getotp")
    @ResponseBody
    public CommonReturnType getOtp(@RequestParam(name = "telphone") String telphone)
            throws BusinessException {
        if (userService.getUserByTelePhone(telphone) != null) {
            throw new BusinessException(EmBusinessError.USER_REGISTRED_ERROR);
        }

        //按照一定的规则生成otp验证码
//        Random random = new Random();
//        int randomInt = random.nextInt(99999);
//        randomInt += 10000;
//        String otpCode = String.valueOf(randomInt);
        String otpCode = "0000";

        //奖otp验证码和对应的telphone形成对应关系
//        httpServletRequest.getSession().setAttribute(telphone, otpCode);

        //奖otp以短信的形式发送给用户
//        System.out.println("telphone=" + telphone + "&otpCode=" + otpCode);
//        SendSms.send(telphone, otpCode);

        return CommonReturnType.create(null);
    }

    //用户注册接口
    @RequestMapping(value = "/register")
    @ResponseBody
    public CommonReturnType register(@RequestParam(name = "telephone") String telephone,
                                     @RequestParam(name = "otpCode") String otpCode,
                                     @RequestParam(name = "password") String password,
                                     @RequestParam(name = "name") String name)
            throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //验证手机验证码
        //String inSessionOtpCode = (String) this.httpServletRequest.getSession().getAttribute(telephone);
        String inSessionOtpCode = "0000";
        if (!StringUtils.equals(otpCode, inSessionOtpCode)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "验证码错误");
        }

        //用户注册流程
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(0);
        userModel.setGeder(new Byte(String.valueOf(1)));
        userModel.setTelphone(telephone);
        userModel.setRegisterMode("byphone");
        userModel.setEncrptPassword(EncodeUtil.Encode(password));

        String ip = IpUtil.getIpAddr(request);

        userService.register(userModel, ip);
        return CommonReturnType.create(null);
    }

    @RequestMapping(value = "/login")
    @ResponseBody
    public CommonReturnType login(@RequestParam(name = "telephone") String telephone,
                                  @RequestParam(name = "password") String password)
            throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //验证参数合法性
        if (StringUtils.isEmpty(telephone) || StringUtils.isEmpty(password)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }

        //没有审核的用户不允许登录
        if (userService.getUserByTelePhone(telephone).getUserType() == -1) {
            throw new BusinessException(EmBusinessError.USER_NOT_EXAMINE_ERROR);
        }
        String ip = IpUtil.getIpAddr(request);
        UserModel userModel = userService.validateLogin(telephone, EncodeUtil.Encode(password), ip);

        String token = UUIDUtil.getShortUUID();
        //todo 这里的token还没有设置到数据库，但是貌似没有太大的用处
        userModel.setToken(token);


        Map<String, List<String>> resourceMap = userService.getResourceMap(userModel.getId().toString());

        userModel.setPageList(resourceMap.get("pageList"));
        userModel.setRequestList(resourceMap.get("requestList"));


        redisTemplate.opsForValue().set(token, JSON.toJSONString(userModel), 3600, TimeUnit.SECONDS);
        response.setHeader("Set-Cookie", "token=" + token + ";Path=/; secure; httponly; samesite=none");
        return CommonReturnType.create(convertFromUserModel(userModel));
    }

    @RequestMapping(value = "/logout")
    @ResponseBody
    public CommonReturnType logout() throws BusinessException {
        String token = getUserModelFromSession().getToken();

        userService.logout(getUserModelFromSession().getId(), IpUtil.getIpAddr(request));
        redisTemplate.delete(token);
        LOG.info("redis删除登录信息");
        response.setHeader("Set-Cookie", "Path=/; secure; httponly; samesite=none");
        return CommonReturnType.create(null);
    }


    @RequestMapping(value = "/setAvatar", method = {RequestMethod.POST})
    @ResponseBody
    public CommonReturnType setAvatar(@RequestParam("image") MultipartFile file)
            throws IOException, BusinessException {

        UserModel userModel = getUserModelFromSession();

        System.out.println(file);
        //获取文件的内容
        InputStream is = file.getInputStream();
        //获取原始文件名
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isEmpty(originalFilename)) {
            throw new BusinessException(EmBusinessError.USER_AVATAR_FILE_ERROR);
        }

        if (!originalFilename.toLowerCase(Locale.ROOT).endsWith(".jpg")
                && !originalFilename.toLowerCase().endsWith(".png")
                && !originalFilename.toLowerCase().endsWith(".jpeg")) {
            throw new BusinessException(EmBusinessError.USER_AVATAR_FILE_ERROR);
        }

        //todo 两种文件类型不同
        File newFile = new File(FileUtil.avatarpath + "avatar-" + userModel.getId() + "-" +
                CalendarUtil.getCurrentTimeCode() + ".jpg");

        //确保目录和文件都存在
        FileUtil.checkDirPath(FileUtil.avatarpath);
        FileUtil.checkFile(newFile);

        //将文件输出到目标的文件中
        file.transferTo(newFile);

        //远程的在存储桶中的路径
        String key = "image/avatar/" + newFile.getName();

        CosUtil.uploadAvatar(newFile.getPath(), key);

        String avatarUrl = ConstUtil.cdnUrl + key;

        String token = userModel.getToken();
        userModel = userService.setAvatar(avatarUrl, userModel.getId());
        userModel.setToken(token);
        redisTemplate.delete(userModel.getToken());
        redisTemplate.opsForValue().set(userModel.getToken(), JSON.toJSONString(userModel), 3600, TimeUnit.SECONDS);

        UserVO userVO = convertFromUserModel(userModel);

        return CommonReturnType.create(userVO);
    }

    @RequestMapping("/profile")
    @ResponseBody
    public CommonReturnType getUserProfile(@RequestParam(value = "userId", required = false)
                                                   String userId) throws BusinessException {
        UserModel userModel;
        if (userId == null) {
            userModel = getUserModelFromSession();
        } else {
            userModel = userService.getUserById(userId);
        }

        UserProfileVO userProfileVO = new UserProfileVO();
        BeanUtils.copyProperties(userModel, userProfileVO);

        userProfileVO.setUserId(userModel.getId());

        Set<Integer> acceptList = submissionService.getSubmitProblemIDList(userModel.getId(), 2);
        Set<Integer> allList = submissionService.getSubmitProblemIDList(userModel.getId(), null);
        userProfileVO.setAccept(acceptList.size());
        userProfileVO.setAttempt(allList.size() - acceptList.size());
        List<Integer> solveList = new ArrayList<>(acceptList);
        userProfileVO.setSolveList(solveList);
        List<Integer> attemptList = new ArrayList<>(allList);
        attemptList.removeAll(acceptList);
        userProfileVO.setAttemptList(attemptList);

        Long lastLogin = Collections.max(userService.getUserLoginRecordList(userModel.getId(), 1));
        Long registerTime = System.currentTimeMillis();
        if (userService.getUserLoginRecordList(userModel.getId(), 3).size() != 0) {
            registerTime = userService.getUserLoginRecordList(userModel.getId(), 3).get(0);
        }
        //设置注册时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(registerTime);
        userProfileVO.setCreateTime(
                CalendarUtil.calendarToString(calendar));

        //设置最后的登录时间
        calendar.setTimeInMillis(lastLogin);
        userProfileVO.setLastLogin(CalendarUtil.calendarToString(calendar));


        if (getUserModelFromSession() != null && getUserId().equals(userId)) {
            userProfileVO.setTelephone(userModel.getTelphone());
        }

        return CommonReturnType.create(userProfileVO);
    }


    @RequestMapping("/setEmail")
    @ResponseBody
    public CommonReturnType setEmail(@RequestParam("email") String email) throws BusinessException {
        UserModel userModel = getUserModelFromSession();
        String token = userModel.getToken();
        if (!ValidatorUtil.checkEmail(email)) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "邮箱填写错误");
        }
        userModel = userService.setEmail(email, userModel.getId());
        redisTemplate.delete(token);
        redisTemplate.opsForValue().set(token, JSON.toJSONString(userModel), 3600, TimeUnit.SECONDS);
        UserVO userVO = convertFromUserModel(userModel);
        return CommonReturnType.create(userVO);
    }

    @RequestMapping("/updateBaseInfo")
    @ResponseBody
    public CommonReturnType updateBaseInfo(@RequestBody UserModel userModel) throws BusinessException {
        UserModel oldUserModel = getUserModelFromSession();
        String token = oldUserModel.getToken();
        //设置姓名
        if (!TextUtils.isEmpty(userModel.getName())) {
            oldUserModel.setName(userModel.getName());
        }
        //设置学校
        if (!TextUtils.isEmpty(userModel.getSchool())) {
            oldUserModel.setSchool(userModel.getSchool());
        }
        //设置年级
        if (!TextUtils.isEmpty(userModel.getGrade())) {
            oldUserModel.setGrade(userModel.getGrade());
        }
        //个性签名
//        if (!TextUtils.isEmpty(userModel.())){
//            oldUserModel.setName(userModel.getName());
//        }
        //设置性别
        if (!userModel.getGeder().equals(oldUserModel.getGeder())) {
            oldUserModel.setGeder(userModel.getGeder());
        }

        UserModel newUserModel = userService.updateUserInfo(oldUserModel);
        redisTemplate.delete(token);
        redisTemplate.opsForValue().set(token, JSON.toJSONString(newUserModel), 3600, TimeUnit.SECONDS);
        return CommonReturnType.create(newUserModel);
    }

    @RequestMapping("/loginRecord")
    @ResponseBody
    public CommonReturnType getLoginRecord() throws BusinessException {
        List<Long> loginRecordList = userService
                .getUserLoginRecordList(getUserId(), ConstUtil.LoginRecordType.LoginRecord);
        List<Long> logoutRecordList = userService
                .getUserLoginRecordList(getUserId(), ConstUtil.LoginRecordType.LoginRecord);
        Map<String, List<Long>>
                result = new HashMap<>();
        result.put("loginRecordList", loginRecordList);
        result.put("logoutRecordList", logoutRecordList);
        return CommonReturnType.create(result);
    }

    private UserVO convertFromUserModel(UserModel userModel) {
        if (userModel == null) {
            return null;
        }

        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userModel, userVO);
        return userVO;
    }

    private String getUserId() throws BusinessException {
        return getUserModelFromSession().getId();
    }

}
